import { ElMessage, ElLoading } from 'element-plus'
import { handleMockRequest } from '@/mock/api.js'

// ==================== 配置常量 ====================

/**
 * 是否启用Mock模式
 * 设置为true时，所有API请求都会返回Mock数据
 */
const USE_MOCK = true

/**
 * API 基础地址配置
 * 开发环境使用代理路径 /api，生产环境使用根路径
 */
const BASE_URL = process.env.NODE_ENV === 'development' ? '/api' : '/'

/**
 * 请求超时时间（毫秒）
 */
const REQUEST_TIMEOUT = 60000

/**
 * 需要重新登录的错误消息列表
 */
const LOGIN_REQUIRED_MESSAGES = [
  '登录超时，请重新登录！',
  '您已被踢下线！',
  '抱歉，该账号已禁用！',
  '禁止非工作时间登录！'
]

/**
 * Loading 管理
 */
let loadingInstance = null
let loadingCount = 0

/**
 * 显示全屏加载遮罩
 * @param {string} text - 加载文本，默认为"正在加载"
 * @param {boolean} showMask - 是否显示遮罩层，默认为true
 */
const showLoading = (text = '正在加载', showMask = true) => {
  if (loadingCount === 0) {
    loadingInstance = ElLoading.service({
      lock: true,
      text: text,
      background: showMask ? 'rgba(0, 0, 0, 0.7)' : 'transparent',
      customClass: showMask ? 'request-loading' : 'request-loading-no-mask'
    })
  }
  loadingCount++
}

/**
 * 隐藏全屏加载遮罩
 */
const hideLoading = () => {
  loadingCount--
  if (loadingCount <= 0) {
    loadingCount = 0
    if (loadingInstance) {
      loadingInstance.close()
      loadingInstance = null
    }
  }
}

// ==================== Axios 实例创建 ====================

/**
 * 创建 axios 实例（仅在非Mock模式下使用）
 * 配置默认的请求参数和头部信息
 */
let request = null
if (!USE_MOCK) {
  // 动态导入axios（仅在需要时）
  import('axios').then(axios => {
    request = axios.default.create({
      baseURL: BASE_URL,
      timeout: REQUEST_TIMEOUT,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })
  })
}

// ==================== 工具函数 ====================

/**
 * 将对象转换为 URL 编码的字符串
 * 用于 POST 请求的数据格式转换
 *
 * @param {Object} data - 要转换的数据对象
 * @returns {string} URL 编码的字符串，如 "key1=value1&key2=value2"
 *
 * @example
 * objectToUrlEncoded({ name: 'John', age: 30 })
 * // 返回: "name=John&age=30"
 */
const objectToUrlEncoded = (data) => {
  // 参数验证：确保输入是有效的对象
  if (!data || typeof data !== 'object') {
    return ''
  }

  // 将对象的键值对转换为 URL 编码格式
  return Object.keys(data)
    .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
    .join('&')
}

// ==================== 请求拦截器 ====================

/**
 * 请求拦截器（仅在非Mock模式下使用）
 * 在请求发送前对请求配置进行处理
 *
 * 主要功能：
 * 1. 显示全屏加载遮罩
 * 2. 处理不同类型的请求数据格式
 * 3. 文件上传时自动设置正确的 Content-Type
 * 4. 普通 POST 请求数据转换为 URL 编码格式
 */
if (!USE_MOCK && request) {
  request.interceptors.request.use(
    (config) => {
      // 显示加载遮罩（除非明确禁用）
      if (config.showLoading !== false) {
        const loadingText = config.loadingText || '正在加载'
        const showMask = config.showMask !== false
        showLoading(loadingText, showMask)
      }

      // 处理文件上传请求
      if (config.data instanceof FormData) {
        // 文件上传时删除默认的 Content-Type，让浏览器自动设置正确的边界值
        delete config.headers['Content-Type']
        return config
      }

      // 处理普通 POST 请求的数据格式转换
      if (config.method === 'post' && config.data && typeof config.data === 'object') {
        // 将对象数据转换为 URL 编码格式，符合后端接收要求
        config.data = objectToUrlEncoded(config.data)
      }

      return config
    },
    (error) => {
      // 请求配置错误时隐藏加载遮罩
      hideLoading()
      console.error('请求拦截器错误:', error)
      return Promise.reject(error)
    }
  )
}

// ==================== 响应拦截器 ====================

/**
 * 清除用户认证信息并跳转到指定页面
 * @param {string} redirectPath - 跳转路径
 */
const clearAuthAndRedirect = (redirectPath) => {
  localStorage.clear()
  window.location.href = redirectPath
}

/**
 * 检查是否为需要重新登录的错误消息
 * @param {string} message - 错误消息
 * @returns {boolean} 是否需要重新登录
 */
const isLoginRequiredMessage = (message) => {
  return LOGIN_REQUIRED_MESSAGES.includes(message)
}

/**
 * 响应拦截器（仅在非Mock模式下使用）
 * 统一处理服务器响应数据和错误状态
 *
 * 响应数据结构约定：
 * {
 *   status: 1,        // 1-成功，0-失败
 *   msg: "消息内容",   // 提示消息
 *   data: {}          // 业务数据
 * }
 */
if (!USE_MOCK && request) {
  request.interceptors.response.use(
    (response) => {
      // 隐藏加载遮罩
      hideLoading()

      const { data } = response

      // 处理有结构化响应的情况
      if (data && typeof data === 'object' && data.hasOwnProperty('status')) {

        // 请求成功的情况
        if (data.status === 1) {
          return data
        }

        // 请求失败的情况，根据错误消息类型进行不同处理
        const errorMessage = data.msg || '系统异常'

        // 处理非法请求
        if (data.msg === '非法请求！') {
          clearAuthAndRedirect('/404')
          return
        }

        // 处理需要重新登录的情况
        if (isLoginRequiredMessage(data.msg)) {
          ElMessage.error(errorMessage)
          clearAuthAndRedirect('/login')
          return
        }

        // 处理其他业务错误
        ElMessage.error(errorMessage)
        return Promise.reject(new Error(errorMessage))
      }

      // 没有 status 字段的响应，直接返回数据
      return data
    },
    (error) => {
      // 隐藏加载遮罩
      hideLoading()

      console.error('响应拦截器错误:', error)

      // 处理 HTTP 状态码错误
      if (error.response) {
        const { status, data } = error.response
        let errorMessage = '请求失败'

        // 根据 HTTP 状态码提供具体的错误信息
        switch (status) {
          case 400:
            errorMessage = data?.msg || '请求参数错误'
            break
          case 401:
            errorMessage = '未授权，请重新登录'
            clearAuthAndRedirect('/login')
            break
          case 403:
            errorMessage = '拒绝访问，权限不足'
            break
          case 404:
            errorMessage = '请求的资源不存在'
            break
          case 500:
            errorMessage = '服务器内部错误，请稍后重试'
            break
          case 502:
            errorMessage = '网关错误，服务暂时不可用'
            break
          case 503:
            errorMessage = '服务不可用，请稍后重试'
            break
          default:
            errorMessage = data?.msg || `请求失败 (状态码: ${status})`
        }

        ElMessage.error(errorMessage)
      } else if (error.request) {
        // 网络连接错误（请求已发出但没有收到响应）
        ElMessage.error('网络连接失败，请检查网络设置')
      } else {
        // 请求配置错误或其他错误
        ElMessage.error(error.message || '请求失败')
      }

      return Promise.reject(error)
    }
  )
}

// ==================== API 方法封装 ====================

/**
 * GET 请求方法
 * 用于获取数据，参数通过 URL 查询字符串传递
 *
 * @param {string} url - 请求的 API 地址
 * @param {Object} params - 查询参数对象
 * @param {Object} options - 请求选项
 * @param {string} options.loadingText - 自定义加载文本
 * @param {boolean} options.showLoading - 是否显示加载遮罩，默认true
 * @param {boolean} options.showMask - 是否显示遮罩层，默认true
 * @returns {Promise<any>} 返回请求的 Promise 对象
 *
 * @example
 * // 获取用户列表
 * get('/users', { page: 1, size: 10 })
 *   .then(response => { 处理响应数据  })
 *   .catch(error => console.error(error))
 *
 * // 自定义加载文本
 * get('/users', { page: 1 }, { loadingText: '正在获取用户列表' })
 *
 * // 禁用加载遮罩
 * get('/users', { page: 1 }, { showLoading: false })
 *
 * // 显示加载但不显示遮罩层
 * get('/users', { page: 1 }, { showMask: false })
 */
export const get = async (url, params = {}, options = {}) => {
  if (USE_MOCK) {
    // Mock模式：显示加载遮罩并返回Mock数据
    if (options.showLoading !== false) {
      const loadingText = options.loadingText || '正在加载'
      const showMask = options.showMask !== false
      showLoading(loadingText, showMask)
    }

    try {
      const response = await handleMockRequest(url, params)
      hideLoading()
      return response
    } catch (error) {
      hideLoading()
      throw error
    }
  } else {
    // 真实请求模式
    return request.get(url, {
      params,
      loadingText: options.loadingText,
      showLoading: options.showLoading,
      showMask: options.showMask
    })
  }
}

/**
 * POST 请求方法
 * 用于创建新资源，数据通过请求体传递
 *
 * @param {string} url - 请求的 API 地址
 * @param {Object|FormData} data - 请求体数据
 * @param {Object} options - 请求选项
 * @param {string} options.loadingText - 自定义加载文本
 * @param {boolean} options.showLoading - 是否显示加载遮罩，默认true
 * @param {boolean} options.showMask - 是否显示遮罩层，默认true
 * @returns {Promise<any>} 返回请求的 Promise 对象
 *
 * @example
 * // 创建新用户
 * post('/users', { name: 'John', email: 'john@example.com' })
 *   .then(response => { /* 处理创建成功  })
 *   .catch(error => console.error('创建失败:', error))
 *
 * // 自定义加载文本
 * post('/users', { name: 'John' }, { loadingText: '正在创建用户' })
 *
 * // 禁用加载遮罩
 * post('/users', { name: 'John' }, { showLoading: false })
 *
 * // 显示加载但不显示遮罩层
 * post('/users', { name: 'John' }, { showMask: false })
 */
export const post = async (url, data = {}, options = {}) => {
  if (USE_MOCK) {
    // Mock模式：显示加载遮罩并返回Mock数据
    if (options.showLoading !== false) {
      const loadingText = options.loadingText || '正在加载'
      const showMask = options.showMask !== false
      showLoading(loadingText, showMask)
    }

    try {
      const response = await handleMockRequest(url, data)
      hideLoading()
      return response
    } catch (error) {
      hideLoading()
      throw error
    }
  } else {
    // 真实请求模式
    return request.post(url, data, {
      loadingText: options.loadingText,
      showLoading: options.showLoading,
      showMask: options.showMask
    })
  }
}



// ==================== 默认导出 ====================

/**
 * 导出请求实例，供需要更复杂配置的场景使用
 * 在Mock模式下，这将是一个模拟的请求处理器
 *
 * @example
 * import request from '@/utils/request'
 *
 * // 使用自定义配置（仅在非Mock模式下有效）
 * if (!USE_MOCK) {
 *   request({
 *     method: 'post',
 *     url: '/api/upload',
 *     data: formData,
 *     headers: { 'Content-Type': 'multipart/form-data' }
 *   })
 * }
 */
export default USE_MOCK ? {
  get: (url, config) => get(url, config?.params || {}, config || {}),
  post: (url, data, config) => post(url, data, config || {})
} : request
